import base64
import hashlib
import hmac
import json
import time
import uuid
from urllib.parse import urlencode, quote
import requests
from datetime import datetime, timezone, timedelta

class Credential:
    def __init__(self, AK, SK):
        self.AK = AK
        self.SK = SK

    def get_ctapi_sorted_query_string(self, query):
        query_array = [f"{quote(key)}={quote(value)}" for key, value in sorted(query.items())]
        query_string = '&'.join(query_array)
        return query_string

    def generate_uuid(self):
        return str(uuid.uuid4())

    def signature_method(self, key, message, algorithm):
        return hmac.new(key, message, algorithm).digest()

    def get_ctapi_authorization(self, query, body, uuid, ak, sk, timestamp):
        hashed_request_body = hashlib.sha256(body.encode()).hexdigest()
        signature = f"ctyun-eop-request-id:{uuid}\neop-date:{timestamp}\n\n{query}\n{hashed_request_body}"
        ktime = self.signature_method(sk.encode(), timestamp.encode(), hashlib.sha256)
        kak = self.signature_method(ktime, ak.encode(), hashlib.sha256)
        kdate = self.signature_method(kak, timestamp[:8].encode(), hashlib.sha256)
        signa_sha256 = self.signature_method(kdate, signature.encode(), hashlib.sha256)
        base64_signa = base64.b64encode(signa_sha256).decode()
        sign_header = f"{ak} Headers=ctyun-eop-request-id;eop-date Signature={base64_signa}"
        return sign_header

    def do_ctapi_request(self, request):
        # 必填字段
        req_url = request['url']
        method = request['method']
        headers = request['headers']
        # 非必填
        data = request.get('data', {})
        query = request.get('query', {})

        query_str = self.get_ctapi_sorted_query_string(query)
        if query_str:
            req_url += f"?{query_str}"

        req_body = ''
        if data:
            if headers['Content-Type'] == 'application/json':
                req_body = json.dumps(data)
                headers['Content-Type'] = 'application/json; charset=utf-8'
            else:
                req_body = urlencode(data)
                headers['Content-Type'] = 'application/x-www-form-urlencoded'

        uuid = self.generate_uuid()
        # YYYYMMDDTHHmmssZ格式时间戳，asia/shanghai时区
        eop_date = datetime.now(timezone(timedelta(hours=8))).strftime("%Y%m%dT%H%M%SZ")
        authorization = self.get_ctapi_authorization(query_str, req_body, uuid, self.AK, self.SK, eop_date)

        config = {
            'headers': {
                **headers,
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/110.0',
                'Ctyun-Eop-Request-Id': uuid,
                'Eop-Date': eop_date,
                'Eop-Authorization': authorization,
            },
        }

        response = requests.request(method, req_url, headers = config['headers'], data=req_body, verify = False)
        if response.status_code == 200:
            print(f"openapi request success.")
            return json.loads(response.text)
        else:
            print(f"openapi request failed, status code: {response.status_code}, reason: {response.reason}")
            return ValueError(f"openapi request failed, status code: {response.status_code}, reason: {response.reason}")